﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;

using System.IO;
using System.Threading;
using System.Windows.Forms;

using Codeer.Friendly.Dynamic;
using Codeer.Friendly;
using Codeer.Friendly.Windows;
using Codeer.Friendly.Windows.NativeStandardControls;
using Codeer.Friendly.Windows.Grasp;

namespace STAR.RunnerFramework
{
    public class RunnerBase
    {
        public string TargetPath { get; set; }
        public string LogFilePath { get; set; }

        public int WaitTime { get; set; }
        public bool WaitFlag { get; set; }

        private Process _process;
        private List<ControlInfo> _controlInfoList;

        private WindowsAppFriend t_app;
        private dynamic t_mainForm;

        public RunnerBase()
        {
            WaitFlag = false;
            WaitTime = 1000;
        }

        public void SetUp()
        {
            LaunchTarget();
            SetUpControls();
        }


        public void SetUp(Process process)
        {
            this._process = process;
            SetUpProcess();
            SetUpControls();
        }

        public void TearDown()
        {
            if (_process.HasExited == false)
            {
                _process.Kill();
            }
        }

        public void LaunchTarget()
        {
            _process = Process.Start(this.TargetPath);
            SetUpProcess();
        }
        
        private void SetUpProcess()
        {
            _controlInfoList = new List<ControlInfo>();
            t_app = new WindowsAppFriend(_process);
            t_mainForm = t_app.Type<Application>().OpenForms[0];
            t_mainForm.Activate();
        }

        public string GetMainFormTitle()
        {
            return t_mainForm.Text;
        }

        public int SetUpControls()
        {
            int count = t_mainForm.Controls.Count;
            ControlInfo newInfo;

            for (int i = 0; i < count; ++i)
            {
                dynamic tName = t_mainForm.Controls[i].Name;
                dynamic tControlType = t_mainForm.Controls[i].GetType();

                dynamic tTabIndex = t_mainForm.Controls[i].TabIndex;
                newInfo = new ControlInfo();
                newInfo.Name = tName.ToString();
                newInfo.TabIndex = (int)tTabIndex;


                string fullName = tControlType.FullName.ToString();

                if (fullName == "System.Windows.Forms.Label")
                {
                    newInfo.Category = ControlInfo.ControlCategory.Label;
                }
                else if(fullName == "System.Windows.Forms.Button")
                {
                    newInfo.Category = ControlInfo.ControlCategory.Button; 
                }
                else if (fullName == "System.Windows.Forms.NumericUpDown")
                {
                    newInfo.Category = ControlInfo.ControlCategory.NumericUpDown;
                }
                else if (fullName == "System.Windows.Forms.GroupBox")
                {
                    newInfo.Category = ControlInfo.ControlCategory.GroupBox;
                }
                else 
                {
                    newInfo.Category = ControlInfo.ControlCategory.None;
                }

                _controlInfoList.Add(newInfo);
             }

            return count;
        }

        public int GetControlCount()
        {
            return _controlInfoList.Count;
        }

        public string GetControlName(int index)
        {
            return _controlInfoList[index].Name;
        }

        public ControlInfo GetInfo(int index)
        {
            return _controlInfoList[index];
        }

        public void SetValue(string controlName, decimal value)
        {
            int index = GetControlIndex(controlName);
            ControlInfo info = _controlInfoList[index];

            (t_mainForm.Controls[index]).Focus();
            TakeWait();
            if (info.Category == ControlInfo.ControlCategory.NumericUpDown)
            {
                WriteLog(String.Format("NumericUpDown[{0}]値[{1}]セット", controlName, value));
                t_mainForm.Controls[index].Value = value;
            }
            else if (info.Category == ControlInfo.ControlCategory.Label)
            {
                WriteLog(String.Format("Label[{0}]値[{1}]セット", controlName, value.ToString()));
                t_mainForm.Controls[index].Text = value.ToString();
            }
        }

        public void SetValue(string controlName, string value)
        {
            int index = GetControlIndex(controlName);
            ControlInfo info = _controlInfoList[index];

            (t_mainForm.Controls[index]).Focus();
            TakeWait();
            if (info.Category == ControlInfo.ControlCategory.GroupBox)
            {
                dynamic tRadioButtonList = t_mainForm.Controls[index].Controls;
                int count = tRadioButtonList.Count;

                for (int i = 0; i < count; ++i)
                {
                    dynamic tRadioButton = tRadioButtonList[i];
                    string name = tRadioButton.Name;
                    if ( name == value )
                    {
                        WriteLog(String.Format("GroupBox[{0}]をチェック", name));
                        tRadioButton.Checked = true;
                        break;
                    }
                }
            }
        }

        public void SetValueAndMessageBox(string controlName, string value, string button)
        {
            int index = GetControlIndex(controlName);
            ControlInfo info = _controlInfoList[index];

            (t_mainForm.Controls[index]).Focus();
            TakeWait();
            if (info.Category == ControlInfo.ControlCategory.GroupBox)
            {
                dynamic tRadioButtonList = t_mainForm.Controls[index].Controls;
                int count = tRadioButtonList.Count;

                for (int i = 0; i < count; ++i)
                {
                    dynamic tRadioButton = tRadioButtonList[i];
                    string name = tRadioButton.Name;
                    if (name == value)
                    {
                        var async1 = new Async();
                        WriteLog(String.Format("GroupBox[{0}]をチェック", name));
                        tRadioButton.Checked(true,async1);
                        TakeWait();
                        WriteLog(String.Format("Messageboxの[{0}]を押下", button));
                        CloseMessagebox(button);
                        async1.WaitForCompletion();
                        break;
                    }
                }
            }
        }

        private void CloseMessagebox(string button)
        {
            WindowControl dlg = WindowControl.FromZTop(t_app); ;
            var msgBox = new NativeMessageBox(dlg);
            msgBox.EmulateButtonClick(button);
        }

        public void SetKeywordValues(string[] values)
        {
            foreach(string value in values)
            {
                //文字列の先頭が[#]の場合は、コメント扱いとして処理しない
                if(string.IsNullOrWhiteSpace(value) == false &&
                   value.Substring(0,1) != "#" )
                {
                    string[] parts = value.Split('\t');
                    if ( parts.Length >= 2)
                    {
                        if (parts.Length >= 3 && parts[2].ToUpper().Trim() == "CLICK")
                        {
                            Invoke(parts[0]);
                        }
                        else if (parts.Length >= 3 && parts[2].ToUpper().Trim() == "LOG")
                        {
                            string text = "";
                            if (string.IsNullOrWhiteSpace(parts[0]) == true)
                            {
                                text = parts[1];
                            }
                            else
                            {
                                text = string.Format(parts[1], GetText(parts[0]));
                            }
                            WriteLog(text);
                        }
                        else if (parts.Length >= 3 && parts[2].ToUpper().Trim() == "WAIT")
                        {
                            int waitTime = 100;

                            if (string.IsNullOrWhiteSpace(parts[1]) == true)
                            {
                                waitTime = int.Parse(parts[1]);
                            }
                            System.Threading.Thread.Sleep(waitTime);
                        }
                        else
                        {
                            int index = GetControlIndex(parts[0]);
                            ControlInfo info = _controlInfoList[index];
                            if(info.Category == ControlInfo.ControlCategory.NumericUpDown)
                            {
                                SetValue(parts[0], decimal.Parse(parts[1]));
                            }
                            else if(info.Category == ControlInfo.ControlCategory.GroupBox)
                            {
                                string[] keys = null;

                                if (parts.Length >= 3) {
                                    keys = parts[2].Split('=');
                                }

                                if (parts.Length >= 3 && keys[0] == "メッセージ")
                                {
                                    SetValueAndMessageBox(parts[0], parts[1], keys[1]);
                                }
                                else
                                {
                                    SetValue(parts[0], parts[1]);
                                }
                            }
                        }
                    }
                }
            }
        }

        public void WriteLog(string newLine)
        {
            if (string.IsNullOrWhiteSpace(LogFilePath) == false)
            {
                string writeLine = string.Format("{0}\r\n", newLine);
                System.IO.File.AppendAllText(LogFilePath, writeLine);
            }
        }

        private int GetControlIndex(string controlName)
        {
            int index;
            for (index = 0; index < _controlInfoList.Count; ++index)
            {
                if (_controlInfoList[index].Name == controlName)
                {
                    break;
                }
            }
            return index;
        }

        public string GetText(string controlName)
        {
            string text = "";
            int index = GetControlIndex(controlName);
            ControlInfo info = _controlInfoList[index];

            if (info.Category == ControlInfo.ControlCategory.Label)
            {
                text = t_mainForm.Controls[index].Text.ToString();
            }
            else if (info.Category == ControlInfo.ControlCategory.NumericUpDown)
            {
                text = t_mainForm.Controls[index].Value.ToString();
            }
            else if (info.Category == ControlInfo.ControlCategory.GroupBox)
            {
                dynamic tRadioButtonList = t_mainForm.Controls[index].Controls;
                int count = tRadioButtonList.Count;

                for (int i = 0; i < count; ++i)
                {
                    dynamic tRadioButton = tRadioButtonList[i];
                    bool checkFlag = tRadioButton.Checked;
                    if (checkFlag == true)
                    {
                        text = tRadioButton.Name;
                        break;
                    }
                }
            }
            return text;
        }

        public decimal GetValue(string controlName)
        {
            decimal value=0;
            int index = GetControlIndex(controlName);
            ControlInfo info = _controlInfoList[index];

            if (info.Category == ControlInfo.ControlCategory.Label)
            {
                value = decimal.Parse( t_mainForm.Controls[index].Text.ToString());
            }
            else if (info.Category == ControlInfo.ControlCategory.NumericUpDown)
            {
                value = t_mainForm.Controls[index].Value;
            }

            return value;
        }

        public void Invoke(string controlName)
        {
            int index = GetControlIndex(controlName);
            ControlInfo info = _controlInfoList[index];

            if(info.Category == ControlInfo.ControlCategory.Button )
            {
                (t_mainForm.Controls[index]).Focus();
                TakeWait();
                EventArgs e = new EventArgs();
                t_mainForm.Controls[index].OnClick(e);
                TakeWait();
            }
        }

        private void TakeWait()
        {
            if( WaitFlag == true )
            {
                System.Threading.Thread.Sleep(WaitTime);
            }
        }

    }
}
